1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.util.time;
12 import core.stdc.time;
13 
14 version(Windows)
15 {
16     import hip.util.windows;
17     extern(Windows) BOOL QueryPerformanceFrequency(LARGE_INTEGER* lpPerformanceCount) nothrow;
18     extern(Windows) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount) nothrow;
19 }
20 else version(PSVita)
21 {
22     extern(C) ulong get_psv_time() @nogc nothrow;
23 }
24 else version(WebAssembly)
25 {
26     extern(C) float monotimeNow() @nogc nothrow;
27 }
28 else
29 {
30     import core.stdc.config:c_long;
31     version(PSVita)
32     {
33         enum CLOCK_MONOTONIC = 4;
34     }
35     else
36     {
37         enum CLOCK_MONOTONIC = 1;
38     }
39     struct timespec
40     {
41         int tv_sec; //Seconds
42         c_long tv_nsec; //Nanoseconds
43     }
44     extern(C) int clock_gettime(int clock_id, timespec* tm) nothrow;
45 }
46 
47 ulong getSystemTime() nothrow
48 {
49     version(Windows)
50     {
51         LARGE_INTEGER counter = void;
52         QueryPerformanceCounter(&counter);
53         return counter.QuadPart * 1_000_000_000; //Convert to nanos
54     }
55     else version(WebAssembly)
56     {
57         return cast(ulong)(monotimeNow() * 1_000_000); //ms to nano
58     }
59     else version(PSVita)
60     {
61         return get_psv_time() * 1_000; //MicroSeconds to Nano
62     }
63     else
64     {
65         timespec tm = void;
66         if(clock_gettime(CLOCK_MONOTONIC, &tm) != 0)
67             return 0;
68         return cast(size_t)(tm.tv_nsec + tm.tv_sec * 1e9);
69     }
70 }
71 private ulong getSystemTicksPerSecond() nothrow
72 {
73     version(Windows)
74     {
75         LARGE_INTEGER ticksPerSecond = void;
76         QueryPerformanceFrequency(&ticksPerSecond);
77         return ticksPerSecond.QuadPart;
78     }
79     else
80     {
81         return 0;
82     }
83 }
84 
85 class HipTime
86 {
87 
88     private __gshared ulong startTime;
89     private __gshared ulong ticksPerSecond;
90     protected __gshared long[string] performanceMeasurement;
91 
92     static void initialize()
93     {
94         ticksPerSecond = getSystemTicksPerSecond();
95         startTime =  getSystemTime();
96     }
97 
98     static long getCurrentTime() nothrow
99     {
100         ulong time = 0;
101         version(Windows)
102         {
103             time = (getSystemTime() - startTime) / ticksPerSecond;
104         }
105         else
106             time = getSystemTime() - startTime;
107         return time;
108     }
109     static double getCurrentTimeDouble() nothrow
110     {
111         version(PSVita)
112             return Double(getCurrentTime());
113         else
114             return cast(double)getCurrentTime();
115     }
116 
117     ///For some reason, float arithmetic is wrong on PSVita, so, use long instead...
118     static long getCurrentTimeAsMsLong() nothrow
119     {
120         return getCurrentTime() / 1_000_000;
121     }
122 
123     static double getCurrentTimeAsMs() nothrow
124     {
125         return getCurrentTimeDouble() / 1_000_000.0f;
126     }
127     static double getCurrentTimeAsSeconds() nothrow
128     {
129         return getCurrentTimeDouble() / 1_000_000_000;
130     }
131 
132     static void initPerformanceMeasurement(string name)
133     {
134         performanceMeasurement[name] = getCurrentTime();
135     }
136     static void finishPerformanceMeasurement(string name)
137     {
138         // import std.stdio:writeln;
139         // writeln(name, " took ", (getCurrentTime() - performanceMeasurement[name])/1_000_000, "ms");
140     }
141 
142     static struct Profiler
143     {
144         private string name;
145         this(string name){this.name = name;HipTime.initPerformanceMeasurement(name);}
146         ~this(){HipTime.finishPerformanceMeasurement(name);}
147     }
148     static mixin template Profile(string name){mixin("HipTime.Profiler _profile"~name~" = HipTime.Profiler("~name~");");}
149     static mixin template ProfileFunction(){mixin("HipTime.Profiler _profileFunc = HipTime.Profiler(__PRETTY_FUNCTION__);");}
150 }
151 
152 float seconds(float v){return v;}
153 float msecs(float v){return v*1_000;}
154 float usecs(float v){return v*1_000_000;}
155 float nsecs(float v){return v*1_000_000_000;}